﻿#include"XQRCode.h"
#include"rscode.h"
#include<QPainter>
#define MAX_CODE_WORD   292  //最大码字容量
#define MAX_DATA_CODE   232  //最大数据码字
#define MAX_RSEC_CODE   146  //最大纠错码字
#define MAX_QRCODE_SIZE 53   //最大矩阵大小(版本9)
typedef struct
{
	unsigned short version;		          //版本1~40
	unsigned short code_word_count; 	  //码字总数=数据码字+纠错码字
	unsigned short data_code_count;	      //数据码字
	unsigned short align_point_count;	  //P61 表E1 校正图形 个数
	unsigned short align_point[6];	      //P61 表E1 校正图形	行列坐标
	unsigned short rsec_block;		      //纠错块数
	unsigned short rsec_block_code_count; //分块码字总数
	unsigned short rsec_block_data_count; //分块数据码数
} qrcode_info_t;

//P28 表9 QR码符号各版本的参数
static const qrcode_info_t m_qrcode_info[] =
{
	{0},
	{1,  26,  19, 0,   0,   0,   0,   0,   0,   0, 1,  26,  19},
	{2,  44,  34, 1,  18,   0,   0,   0,   0,   0, 1,  44,  34},
	{3,  70,  55, 1,  22,   0,   0,   0,   0,   0, 1,  70,  55},
	{4, 100,  80, 1,  26,   0,   0,   0,   0,   0, 1, 100,  80},
	{5, 134, 108, 1,  30,   0,   0,   0,   0,   0, 1, 134, 108},
	{6, 172, 136, 1,  34,   0,   0,   0,   0,   0, 2,  86,  68},
	{7, 196, 156, 2,  22,  38,   0,   0,   0,   0, 2,  98,  78},
	{8, 242, 194, 2,  24,  42,   0,   0,   0,   0, 2, 121,  97},
	{9, 292, 232, 2,  26,  46,   0,   0,   0,   0, 2, 146, 116}
};

XQRCode::XQRCode()
{
	m_data_code.resize(MAX_DATA_CODE);
	m_rsec_code.resize(MAX_RSEC_CODE);
	m_code_word.resize(MAX_CODE_WORD);
	m_qrcode_data.resize(MAX_QRCODE_SIZE);
	for (auto&data: m_qrcode_data)
	{
		data.resize(MAX_QRCODE_SIZE);
	}
}
XQRCode::XQRCode(const QString& text)
	:XQRCode()
{
	qrcode_encode(text);
}
QPixmap XQRCode::to_Pixmap(const QString& text, int width, const QColor& backColor, const QColor& color)
{
	XQRCode code(text);
	return code.to_Pixmap(width,backColor,color);
}
QPixmap XQRCode::to_Pixmap_black(const QString& text, int width)
{
	XQRCode code(text);
	return code.to_Pixmap_black(width);
}
QPixmap XQRCode::to_Pixmap_white(const QString& text, int width)
{
	XQRCode code(text);
	return code.to_Pixmap_white(width);
}
int XQRCode::data_size() const
{
	return m_qrcode_size;
}

QVector<QVector<unsigned char>> XQRCode::data() const
{
	QVector<QVector<unsigned char>> list;
	auto size = m_qrcode_size;
	for (int i=0;i< size;i++)
	{
		QVector<unsigned char> row;
		for (int j = 0; j < size; j++)
		{
			row.append(m_qrcode_data[i][j]);
		}
		list.append(std::move(row));
	}
	return list;
}

QPixmap XQRCode::to_Pixmap(int width ,const QColor& backColor, const QColor& color)
{
	if (backColor == color|| width<1)
		return QPixmap();//颜色不能相同宽度不能小于1
	auto data_size = this->data_size();
	QPixmap pixmap((m_qrcode_size + 1) * width, (m_qrcode_size+1)*width); // 创建一个宽度为 width，高度为 height 的 QPixmap 对象
	pixmap.fill(backColor); // 将 QPixmap 的背景颜色
	QPainter painter(&pixmap); // 使用 QPixmap 对象作为绘制设备创建 QPainter 对象
	for (int i = 0; i < data_size; i++)
	{
		for (int j = 0; j < data_size; j++)
		{
			auto value = m_qrcode_data[i][j];
			(value == 0) ? painter.setPen(QPen(backColor, width)) : painter.setPen(QPen(color, width));
			painter.drawPoint((j+1) * width, (i+1)*width); // 绘制点 (x, y)
		}
	}
	painter.end(); // 结束绘制操作
	return pixmap;
}
void XQRCode::data_outCmd() const
{
	//输出数组
	for (auto& data : data())
	{
		for (auto& value : data)
		{
			printf("%d ", value);
		}
		printf("\r\n");
	}
	printf("\r\n");
}
bool XQRCode::qrcode_encode(const QString& text)
{
	int  version;
	int  data_bits_count;
	int  data_code_count;
	int  code_word_count;
	auto data = text.toUtf8();
	data_bits_count = set_encode_data(data);
	if (data_bits_count == 0)
	{
		return false;
	}
	version = get_encode_version(data_bits_count);
	if (version == 0)
	{
		return false;
	}
	data_code_count = set_padding_byte(version, data_bits_count);
	code_word_count = set_code_word(version, data_code_count);
	format_qrcode_data(version, code_word_count);
	return true;
}

int XQRCode::set_encode_data(const QByteArray& data)
{
	auto size = data.size();
	if ((size + 2) > MAX_DATA_CODE)
	{
		return 0;
	}
	
	memset(&m_data_code[0], 0, MAX_DATA_CODE);
	int count = 0;
	count = set_data_code(count, 0x04, 4); //起始符4bit表示编码类型
	count = set_data_code(count, size, 8);
	for (int i = 0; i < size; i++)
	{
		count = set_data_code(count, (unsigned short)data[i], 8);
	}
	return set_data_code(count, 0x00, 4); //结束符
}

int XQRCode::set_data_code(int index, int data, int size)
{
	int i;
	for (i = 0; i < size; i++)
	{
		if (data & (1 << (size - i - 1)))
		{
			m_data_code[(index + i) / 8] |= 1 << (7 - ((index + i) % 8));
		}
	}
	return index + size;
}

int XQRCode::get_encode_version(int bits_count)
{
	int i;
	for (i = 1; i <= 9; i++)
	{
		if ((bits_count + 7) / 8 <= m_qrcode_info[i].data_code_count)
		{
			return i;
		}
	}
	return 0;
}

int XQRCode::set_padding_byte(int version, int data_bits_count)
{
	int  i;
	int  data_code_count;
	unsigned char  padding_byte = 0xec;
	data_code_count = m_qrcode_info[version].data_code_count;
	for (i = (data_bits_count + 7) / 8; i < data_code_count; i++)
	{
		m_data_code[i] = padding_byte;
		padding_byte = (padding_byte == 0xec) ? 0x11 : 0xec;
	}
	return data_code_count;
}

int XQRCode::set_code_word(int version, int data_code_count)
{
	int i, j;
	int code_word_count;
	int cw_data_index;
	int cw_block_count;
	int cw_block_total;
	int cw_block_index;
	int cw_data_count;
	int cw_rscode_count;

	cw_data_index = 0;
	cw_block_index = 0;
	code_word_count = m_qrcode_info[version].code_word_count;
	cw_block_count = m_qrcode_info[version].rsec_block;
	cw_block_total = cw_block_count;
	cw_data_count = m_qrcode_info[version].rsec_block_data_count;
	memset(&m_code_word[0], 0, code_word_count);
	for (i = 0; i < cw_block_count; i++)
	{
		for (j = 0; j < cw_data_count; j++)
		{
			m_code_word[(cw_block_total * j) + cw_block_index] = m_data_code[cw_data_index++];
		}
		cw_block_index++;
	}
	cw_rscode_count = m_qrcode_info[version].rsec_block_code_count - cw_data_count;
	cw_data_index = 0;
	cw_block_index = 0;
	for (i = 0; i < cw_block_count; i++)
	{
		memset(&m_rsec_code[0], 0, m_rsec_code.size());//初始化数据
		memmove(&m_rsec_code[0], &m_data_code[cw_data_index], cw_data_count);
		rscode_encode(&m_rsec_code[0], cw_data_count, cw_rscode_count);
		for (j = 0; j < cw_rscode_count; j++)
		{
			m_code_word[data_code_count + (cw_block_total * j) + cw_block_index] = m_rsec_code[j];
		}
		cw_data_index += cw_data_count;
		cw_block_index++;
	}
	return code_word_count;
}

void XQRCode::format_qrcode_data(int version, int code_word_count)
{
	int i, j;
	int masking;
	m_qrcode_size = version * 4 + 17;
	//初始化数据
	for (auto&data: m_qrcode_data)
	{
		memset(&data[0], 0, data.size());
	}
	set_function_patterns(version);
	set_code_word_pattern(code_word_count);
	get_masking_pattern(&masking);
	set_masking_pattern(masking);
	set_format_info(masking);
	for (i = 0; i < m_qrcode_size; i++)
	{
		for (j = 0; j < m_qrcode_size; j++)
		{
			m_qrcode_data[i][j] = (m_qrcode_data[i][j] & 0x11) != 0;
		}
	}
}

void XQRCode::set_function_patterns(int version)
{
	int i, j;
	//三个大回字
	set_postion_pattern(0, 0);
	set_postion_pattern(m_qrcode_size - 7, 0);
	set_postion_pattern(0, m_qrcode_size - 7);
	//分隔线
	set_separator_pattern();
	//对齐图案
	for (i = 0; i < m_qrcode_info[version].align_point_count; i++)
	{
		set_alignment_pattern(m_qrcode_info[version].align_point[i], 6);
		set_alignment_pattern(6, m_qrcode_info[version].align_point[i]);
		for (j = 0; j < m_qrcode_info[version].align_point_count; j++)
		{
			set_alignment_pattern(m_qrcode_info[version].align_point[i], m_qrcode_info[version].align_point[j]);
		}
	}
	//标准线
	set_timing_pattern();
	//版本信息
	set_version_info(version);
}

void XQRCode::set_postion_pattern(int x, int y)
{
	const unsigned char pattern[] = { 0x7f,0x41,0x5d,0x5d,0x5d,0x41,0x7f };
	int i, j;
	for (i = 0; i < 7; i++)
	{
		for (j = 0; j < 7; j++)
		{
			m_qrcode_data[x + j][y + i] = (pattern[i] & (1 << (6 - j))) ? 0x30 : 0x20;
		}
	}
}

void XQRCode::set_separator_pattern(void)
{
	int i;
	for (i = 0; i < 8; i++)
	{
		m_qrcode_data[i][7] = m_qrcode_data[7][i] = 0x20;
		m_qrcode_data[m_qrcode_size - 8][i] = m_qrcode_data[m_qrcode_size - 8 + i][7] = 0x20;
		m_qrcode_data[i][m_qrcode_size - 8] = m_qrcode_data[7][m_qrcode_size - 8 + i] = 0x20;
	}
	for (i = 0; i < 9; i++)
	{
		m_qrcode_data[i][8] = m_qrcode_data[8][i] = 0x20;
	}
	for (i = 0; i < 8; i++)
	{
		m_qrcode_data[m_qrcode_size - 8 + i][8] = m_qrcode_data[8][m_qrcode_size - 8 + i] = 0x20;
	}
}

void XQRCode::set_alignment_pattern(int x, int y)
{
	const unsigned char pattern[] = { 0x1f,0x11,0x15,0x11,0x1f };
	int i, j;
	if (m_qrcode_data[x][y] & 0x20)
	{
		return;
	}
	x -= 2;
	y -= 2;
	for (i = 0; i < 5; i++)
	{
		for (j = 0; j < 5; j++)
		{
			m_qrcode_data[x + j][y + i] = (pattern[i] & (1 << (4 - j))) ? 0x30 : 0x20;
		}
	}
}

void XQRCode::set_timing_pattern(void)
{
	int i;
	for (i = 8; i <= (m_qrcode_size - 9); i++)
	{
		m_qrcode_data[i][6] = ((i % 2) == 0) ? 0x30 : 0x20;
		m_qrcode_data[6][i] = ((i % 2) == 0) ? 0x30 : 0x20;
	}
}

void XQRCode::set_version_info(int version)
{
	int i, j;
	int ver_data;
	if (version < 7)
	{
		return;
	}
	ver_data = version << 12;
	for (i = 0; i < 6; i++)
	{
		if (ver_data & (1 << (17 - i)))
		{
			ver_data ^= (0x1f25 << (5 - i));
		}
	}
	ver_data += version << 12;
	for (i = 0; i < 6; i++)
	{
		for (j = 0; j < 3; j++)
		{
			m_qrcode_data[i][m_qrcode_size - 11 + j] = (ver_data & (1 << (i * 3 + j))) ? 0x30 : 0x20;
			m_qrcode_data[m_qrcode_size - 11 + j][i] = m_qrcode_data[i][m_qrcode_size - 11 + j];
		}
	}
}

void XQRCode::set_code_word_pattern(int code_word_count)
{
	int i, j;
	int x = m_qrcode_size;
	int y = m_qrcode_size - 1;
	int kx = 1;
	int ky = 1;
	for (i = 0; i < code_word_count; i++)
	{
		for (j = 0; j < 8; j++)
		{
			while (1)
			{
				x += kx;
				kx *= -1;
				if (kx < 0)
				{
					y += ky;
					if ((y < 0) || (y == m_qrcode_size))
					{
						y = (y < 0) ? 0 : (m_qrcode_size - 1);
						ky *= -1;
						x -= 2;
						if (x == 6)
						{
							x--;
						}
					}
				}
				if ((m_qrcode_data[x][y] & 0x20) == 0x00)
				{
					break;
				}
			}
			m_qrcode_data[x][y] = (m_code_word[i] & (1 << (7 - j))) ? 0x02 : 0x00;
		}
	}
}

void XQRCode::get_masking_pattern(int* mask)
{
	int i;
	int masking;
	int penalty;
	int penalty_min;
	masking = 0;
	penalty_min = ((unsigned)-1) >> 1;
	for (i = 0; i < 8; i++)
	{
		set_masking_pattern(i);
		set_format_info(i);
		penalty = get_penalty_count();
		if (penalty < penalty_min)
		{
			penalty_min = penalty;
			masking = i;
		}
	}
	*mask = masking;
}

void XQRCode::set_masking_pattern(int masking)
{
	int i, j;
	unsigned char mask;
	for (i = 0; i < m_qrcode_size; i++)
	{
		for (j = 0; j < m_qrcode_size; j++)
		{
			if (!(m_qrcode_data[j][i] & 0x20))
			{
				switch (masking)
				{
				case 0:
					mask = ((i + j) % 2 == 0) ? 1 : 0;
					break;
				case 1:
					mask = (i % 2 == 0) ? 1 : 0;
					break;
				case 2:
					mask = (j % 3 == 0) ? 1 : 0;
					break;
				case 3:
					mask = ((i + j) % 3 == 0) ? 1 : 0;
					break;
				case 4:
					mask = (((i / 2) + (j / 3)) % 2 == 0) ? 1 : 0;
					break;
				case 5:
					mask = (((i * j) % 2) + ((i * j) % 3) == 0) ? 1 : 0;
					break;
				case 6:
					mask = ((((i * j) % 2) + ((i * j) % 3)) % 2 == 0) ? 1 : 0;
					break;
				default:
					mask = ((((i * j) % 3) + ((i + j) % 2)) % 2 == 0) ? 1 : 0;
					break;
				}
				m_qrcode_data[j][i] = ((m_qrcode_data[j][i] & 0xfe) | (((m_qrcode_data[j][i] & 0x02) > 1) ^ mask));
			}
		}
	}
}

void XQRCode::set_format_info(int masking)
{
	int i;
	int data;
	int info;
	info = 0x08;
	info += masking;
	data = info << 10;
	for (i = 0; i < 5; i++)
	{
		if (data & (1 << (14 - i)))
		{
			data ^= (0x0537 << (4 - i));
		}
	}
	data += info << 10;
	data ^= 0x5412;
	for (i = 0; i <= 5; i++)
	{
		m_qrcode_data[8][i] = (data & (1 << i)) ? 0x30 : 0x20;
	}
	m_qrcode_data[8][7] = (data & (1 << 6)) ? 0x30 : 0x20;
	m_qrcode_data[8][8] = (data & (1 << 7)) ? 0x30 : 0x20;
	m_qrcode_data[7][8] = (data & (1 << 8)) ? 0x30 : 0x20;
	for (i = 9; i <= 14; i++)
	{
		m_qrcode_data[14 - i][8] = (data & (1 << i)) ? 0x30 : 0x20;
	}
	for (i = 0; i <= 7; i++)
	{
		m_qrcode_data[m_qrcode_size - 1 - i][8] = (data & (1 << i)) ? 0x30 : 0x20;
	}
	m_qrcode_data[8][m_qrcode_size - 8] = 0x30;
	for (i = 8; i <= 14; i++)
	{
		m_qrcode_data[8][m_qrcode_size - 15 + i] = (data & (1 << i)) ? 0x30 : 0x20;
	}
}

int XQRCode::get_penalty_count(void)
{
	int i, j, k;
	int penalty;
	int count;
	count = 0;
	penalty = 0;
	for (i = 0; i < m_qrcode_size; i++)
	{
		for (j = 0; j < m_qrcode_size - 4; j++)
		{
			count = 1;
			for (k = j + 1; k < m_qrcode_size; k++)
			{
				if (((m_qrcode_data[i][j] & 0x11) == 0) == ((m_qrcode_data[i][k] & 0x11) == 0))
				{
					count++;
				}
				else
				{
					break;
				}
			}
			if (count >= 5)
			{
				penalty += 3 + (count - 5);
			}
			j = k - 1;
		}
	}
	for (i = 0; i < m_qrcode_size; i++)
	{
		for (j = 0; j < m_qrcode_size - 4; j++)
		{
			count = 1;
			for (k = j + 1; k < m_qrcode_size; k++)
			{
				if (((m_qrcode_data[j][i] & 0x11) == 0) == ((m_qrcode_data[k][i] & 0x11) == 0))
				{
					++count;
				}
				else
				{
					break;
				}
			}
			if (count >= 5)
			{
				penalty += 3 + (count - 5);
			}
			j = k - 1;
		}
	}
	for (i = 0; i < m_qrcode_size - 1; i++)
	{
		for (j = 0; j < m_qrcode_size - 1; j++)
		{
			if ((((m_qrcode_data[i][j] & 0x11) == 0) == ((m_qrcode_data[i + 1][j] & 0x11) == 0)) &&
				(((m_qrcode_data[i][j] & 0x11) == 0) == ((m_qrcode_data[i][j + 1] & 0x11) == 0)) &&
				(((m_qrcode_data[i][j] & 0x11) == 0) == ((m_qrcode_data[i + 1][j + 1] & 0x11) == 0)))
			{
				penalty += 3;
			}
		}
	}
	for (i = 0; i < m_qrcode_size; i++)
	{
		for (j = 0; j < m_qrcode_size - 6; j++)
		{
			if (((j == 0) ||
				(!(m_qrcode_data[i][j - 1] & 0x11))) &&
				(m_qrcode_data[i][j] & 0x11) &&
				(!(m_qrcode_data[i][j + 1] & 0x11)) &&
				(m_qrcode_data[i][j + 2] & 0x11) &&
				(m_qrcode_data[i][j + 3] & 0x11) &&
				(m_qrcode_data[i][j + 4] & 0x11) &&
				(!(m_qrcode_data[i][j + 5] & 0x11)) &&
				(m_qrcode_data[i][j + 6] & 0x11) &&
				((j == m_qrcode_size - 7) || (!(m_qrcode_data[i][j + 7] & 0x11))))
			{
				if (((j < 2 || !(m_qrcode_data[i][j - 2] & 0x11)) &&
					(j < 3 || !(m_qrcode_data[i][j - 3] & 0x11)) &&
					(j < 4 || !(m_qrcode_data[i][j - 4] & 0x11))) ||
					((j >= m_qrcode_size - 8 || !(m_qrcode_data[i][j + 8] & 0x11)) &&
						(j >= m_qrcode_size - 9 || !(m_qrcode_data[i][j + 9] & 0x11)) &&
						(j >= m_qrcode_size - 10 || !(m_qrcode_data[i][j + 10] & 0x11))))
				{
					penalty += 40;
				}
			}
		}
	}
	for (i = 0; i < m_qrcode_size; i++)
	{
		for (j = 0; j < m_qrcode_size - 6; j++)
		{
			if (((j == 0) || (!(m_qrcode_data[j - 1][i] & 0x11))) &&
				(m_qrcode_data[j][i] & 0x11) &&
				(!(m_qrcode_data[j + 1][i] & 0x11)) &&
				(m_qrcode_data[j + 2][i] & 0x11) &&
				(m_qrcode_data[j + 3][i] & 0x11) &&
				(m_qrcode_data[j + 4][i] & 0x11) &&
				(!(m_qrcode_data[j + 5][i] & 0x11)) &&
				(m_qrcode_data[j + 6][i] & 0x11) &&
				((j == m_qrcode_size - 7) || (!(m_qrcode_data[j + 7][i] & 0x11))))
			{
				if (((j < 2 || !(m_qrcode_data[j - 2][i] & 0x11)) &&
					(j < 3 || !(m_qrcode_data[j - 3][i] & 0x11)) &&
					(j < 4 || !(m_qrcode_data[j - 4][i] & 0x11))) ||
					((j >= m_qrcode_size - 8 || !(m_qrcode_data[j + 8][i] & 0x11)) &&
						(j >= m_qrcode_size - 9 || !(m_qrcode_data[j + 9][i] & 0x11)) &&
						(j >= m_qrcode_size - 10 || !(m_qrcode_data[j + 10][i] & 0x11))))
				{
					penalty += 40;
				}
			}
		}
	}
	for (i = 0; i < m_qrcode_size; i++)
	{
		for (j = 0; j < m_qrcode_size; j++)
		{
			if (!(m_qrcode_data[i][j] & 0x11))
			{
				++count;
			}
		}
	}
	if ((50 - ((count * 100) / (m_qrcode_size * m_qrcode_size))) > 0)
	{
		count = 50 - ((count * 100) / (m_qrcode_size * m_qrcode_size));
	}
	else
	{
		count = 0 - (50 - ((count * 100) / (m_qrcode_size * m_qrcode_size)));
	}
	penalty += (count / 5) * 10;
	return penalty;
}

QPixmap XQRCode::to_Pixmap_black(int width)
{
	return to_Pixmap(width,Qt::black, Qt::white);
}
QPixmap XQRCode::to_Pixmap_white(int width)
{
	return to_Pixmap(width, Qt::white, Qt::black);
}